#pragma once
#pragma warning( disable: 4251 ) 

//WGLENGINE_DLL
#ifdef WGLENGINE_DLL
#define WGLENGINE_EXPORT __declspec(dllexport)
#else
#define WGLENGINE_EXPORT __declspec(dllimport)
#endif

#include "GL\glew.h"
#include "glm\glm.hpp"
#include "ShaderUniform.h"

#include <map>
#include <memory>
#include <string>
#include <vector>

class Texture;
class SceneNode;
class WGLENGINE_EXPORT Shader 
{
public:
	enum TextureType {Shadow, Diffuse, Specular, Bump};
	typedef std::map<TextureType, GLuint> TextureMap;

protected:
	TextureMap texParameters;
	
public:
	Shader();
	Shader(std::shared_ptr<Shader> shader)
	{
		this->programID = shader->programID;
		this->vertexShaderID = shader->vertexShaderID;
		this->fragmentShaderID = shader->fragmentShaderID;

		this->vertFilePath = shader->vertFilePath;
		this->fragFilePath = shader->fragFilePath;
	}
	
	~Shader();
	
	virtual GLuint getProgramID();

	void CompileShader();	

	virtual void Bind();	
	virtual void Unbind();

	/*
	std::shared_ptr<Texture> GetTexture(TextureType type)
	{
		if(texParameters.find(type) != texParameters.end())
		{
			return texParameters.at(type);
		}

		return nullptr;
	}*/
	
	std::shared_ptr<FloatShaderUniform> AddParameter(std::string name, float parameter);
	std::shared_ptr<Vec2ShaderUniform> AddParameter(std::string name, glm::vec2 parameter);
	std::shared_ptr<Vec3ShaderUniform> AddParameter(std::string name, glm::vec3 parameter);
	std::shared_ptr<UniformBlockUniform> AddParameter(std::string name, void* uniformBlock, GLuint size, GLuint bindingPt);
	void AddParameter(TextureType type, std::shared_ptr<Texture> texParameter);
	void AddParameter(TextureType type, GLuint texID);
	
	static void InitShaders();
	static void LoadShaders();
	static std::vector<std::string> GetPaths();
	static std::shared_ptr<Shader> GetShader(std::string shaderName);
	static std::map<std::string, std::shared_ptr<Shader>> shaders;
	static std::vector<std::string> paths;

protected:
	virtual void Init();


	GLuint programID;
	GLuint vertexShaderID;
	GLuint fragmentShaderID;

	std::string vertFilePath;
	std::string fragFilePath;

	std::map<std::string, std::shared_ptr<ShaderUniform>> parameters;

private:
	std::string LoadShaderFromFile(std::string filePath);
};
